/*
* BtreeNode.cpp
*
*  Created on: Oct 26, 2011
*      Author: hxu
*/

#include "BtreeNode.h"
#include<cstdlib>
#include<string>
#include<limits>
#include<cmath>
#include "Wire.h"
#include "Btree.h"

using namespace std;

namespace Cxuh {

	void BtreeNode::initBtreeNode() {
		// initialization used for all constructors
		parent = NULL;
		lchild = NULL;
		rchild = NULL;
		name = "";
		dmax = numeric_limits<double>::min();
		dmin = numeric_limits<double>::max();
	}

	BtreeNode::BtreeNode(int id1, char nodetype) :
	TreeNode<int>(nodetype), x(0), y(0), z(0), C(0), R(0) {
		// Auto-generated constructor stub
		initBtreeNode();
		this->id = id1;
	}

	BtreeNode::BtreeNode(int id1, char nodetype, int x1, int y1, int z1) :
	TreeNode<int>(nodetype), x(x1), y(y1), z(z1), C(0), R(0) {
		// Auto-generated constructor stub
		initBtreeNode();
		this->id = id1;
	}

	BtreeNode::~BtreeNode() {
		// Auto-generated destructor stub
	}

	int operator -(const BtreeNode& n1, const BtreeNode& n2) {
		// subtraction of coordinates, Manhattan distance
		int d, d1, d2;
		d1 = n1.getX() - n2.getX();
		d2 = n1.getY() - n2.getY();

		d = abs(d1) + abs(d2);

		return d;
	}

	std::ostream& operator<<(std::ostream& out, BtreeNode& obj) {
		std::string ntype;
		switch (obj.getType()) {
		case CON:
			ntype = "Merge Point : ";
			break;
		case LEAF:
			ntype = "Sink : ";
			break;
		case VIA:
			ntype = "TSV : ";
			break;
		case BUF:
			ntype = "BUF : ";
			break;
		default:
			ntype = "Other : ";
			break;
		}

		out << ntype << obj.getID() << std::endl;
		out << "\tCoordinate : " << obj.getX() << " " << obj.getY() << " "
			<< obj.getZ();
		if (obj.getType() == VIA)
			out << " " << obj.getZ2(); // 2nd tier connected to TSV
		out << std::endl;
		out << "\tCapacitive Load : " << obj.getC() << std::endl;

		return out;
	}

	void BtreeNode::calc_path_delay(){
		// calculate the min and max path delay
		double dlmin = numeric_limits<double>::max(), dlmax = numeric_limits<double>::min();
		double drmin = numeric_limits<double>::max(), drmax = numeric_limits<double>::min();
		double cl = 0, cr = 0;
		double l=0, d=0, d0 = 0;

		if (ntype == LEAF) {
			dmin = 0;
			dmax = 0;
		} else {
			if (lchild) {
				cl = lchild->get_in_cload();
				l = *this - *lchild;
				d = Btree::ELMORE_DISTR * Wire::R * Wire::C * pow(l, 2) + Btree::ELMORE_LUMP * Wire::R * cl * l;
				dlmin = lchild->dmin + d;
				dlmax = lchild->dmax + d;
			}

			if (rchild) {
				cr = rchild->get_in_cload();
				l = *this - *rchild;
				d = Btree::ELMORE_DISTR * Wire::R * Wire::C * pow(l, 2) + Btree::ELMORE_LUMP * Wire::R * cr * l;
				drmin = rchild->dmin + d;
				drmax = rchild->dmax + d;
			}

			d0 = getD() + Btree::ELMORE_LUMP * getR() * (cl + cr); // intrinsic delay

			dmax = max(drmax, dlmax) + d0;
			dmin = min(drmin, dlmin) + d0;
		}
	}

	double BtreeNode::get_in_cload() const{
		// get the c load seen at the input of this node
		double inload = 0;
		int l1 = 0, l2 = 0; // distance between nd and its left and right children
		double c1, c2; // cap of lchild and rchild

		if (this->ntype == BUF || this->ntype == LEAF)
			inload = this->getC();
		else {
			// TSV or merge point
			if (this->lchild) {
				l1 = *this - *(this->lchild);
				c1 = lchild->get_in_cload();
			} else {
				l1 = 0;
				c1 = 0;
			}
			if (this->rchild) {
				l2 = *this - *(this->rchild);
				c2 = rchild->get_in_cload();
			} else {
				l2 = 0;
				c2 = 0;
			}

			inload = this->getC() + (l1 + l2) * Wire::C + c1 + c2;
		}

		return inload;
	}

	void BtreeNode::setXY(int x1, int y1){
		x = x1;
		y = y1;
	}

	void BtreeNode::setXYZ(int x1, int y1, int z1) {
		x = x1;
		y = y1;
		z = z1;
	}
	void BtreeNode::setC(double c) {
		// input cap seen by the predecessor, excluding the children
		C = c;
	}
	void BtreeNode::setR(double r) {
		// output res seen by the successor, excluding the parent and preceding wire
		R = r;
	}

	int BtreeNode::getX() const {
		return x;
	}
	int BtreeNode::getY() const {
		return y;
	}
	int BtreeNode::getZ() const {
		return z;
	}
	int BtreeNode::getZ2() const {
		return z;
	}
	double BtreeNode::getC() const {
		return C;
	}
	double BtreeNode::getR() const {
		return R;
	}

	double BtreeNode::getD() const {
		return 0.0;
	}

	double BtreeNode::get_dmin() const{
		return dmin;
	}

	double BtreeNode::get_dmax() const{
		return dmax;
	}

}
